﻿/// Jasig CAS server emulation with ASP.NET
/// by Uli Trampe
/// http://jasigemu.codeplex.com/
/// 
using System;
using System.Net;
using System.Web;
using System.Xml;

namespace Codeplex.JasigEmu
{
    /// <summary>
    /// Static CAS client class that consumes the basic Jasig CAS functionality.
    /// </summary>
    public static class CasClient
    {
        /// <summary>
        /// Handle Page_Load from Login page
        /// </summary>
        /// <param name="strCasServerUrl"></param>
        /// <param name="strUserName">Returnes the user name when validation has succeeded.</param>
        /// <param name="strErrorText">Returnes the error text when validation has failed.</param>
        /// <returns>Returns true when the call was sucessfully handled.</returns>
        public static bool HandlePageLoad(string strCasServerUrl, out string strUserName, out string strErrorText)
        {
            strUserName = strErrorText = "";
            HttpContext httpContext = HttpContext.Current;

            string strService = httpContext.Request.Url.GetLeftPart(UriPartial.Path);

            // if the logout parameter is given, redirect to CAS logout page
            string strLogout = httpContext.Request.QueryString["logout"];
            if (!String.IsNullOrEmpty(strLogout) && strLogout == "true")
            {
                string strRedirectUrl = BuildLogoutRequest(strCasServerUrl);
                httpContext.Response.Redirect(strRedirectUrl);
                return true;
            }

            // as long there is no ticket given, redirect to the CAS server to retreive one
            string strTicket = httpContext.Request.QueryString["ticket"];
            if (String.IsNullOrEmpty(strTicket))
            {
                string strRedirectUrl = BuildLoginRequest(strCasServerUrl, strService);
                httpContext.Response.Redirect(strRedirectUrl);
                return true;
            }

            // when we have a ticket, then validate it
            string strValidateUrl = BuildServiceValidateRequest(strCasServerUrl, strService, strTicket);

            bool isOK = false;
            try
            {
                // read the XML retuned by the web request
                XmlTextReader reader = new XmlTextReader(new WebClient().OpenRead(strValidateUrl));
                while (reader.Read())
                {
                    if (!reader.IsStartElement()) continue;
                    if (reader.LocalName == "authenticationFailure")
                    {
                        strErrorText = reader.ReadString();
                        break;
                    }
                    if (reader.LocalName == "user")
                    {
                        strUserName = reader.ReadString();
                        isOK = true;
                        break;
                    }
                }
                reader.Close();
            }
            catch (Exception e)
            {
                strErrorText = e.Message;
            }

            return isOK;
        }

        private static string BuildLogoutRequest(string strCasServerUrl)
        {
            return strCasServerUrl + "logout";
        }

        private static string BuildLoginRequest(string strCasServerUrl, string strService)
        {
            return strCasServerUrl + "login?service=" + HttpUtility.UrlEncode(strService);
        }

        private static string BuildServiceValidateRequest(string strCasServerUrl, string strService, string strTicket)
        {
            return strCasServerUrl + "serviceValidate?service=" + HttpUtility.UrlEncode(strService) + "&ticket=" + strTicket;
        }

    }
}
